/*
 * Copyright (c) 2023 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "plugin_manager.h"
#include "dfx/error/av_codec_sample_error.h"
#include <cstdint>

#undef LOG_TAG
#define LOG_TAG "PLUGINMANAGER"

namespace {
int64_t ParseId(napi_env env, napi_callback_info info)
{
    CHECK_AND_RETURN_RET_LOG(env != nullptr && info != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "env or info is null");
    size_t argc = 1;
    napi_value args[1] = {nullptr};
    CHECK_AND_RETURN_RET_LOG(napi_ok == napi_get_cb_info(env, info, &argc, args, nullptr, nullptr),
        AVCODEC_SAMPLE_ERR_ERROR, "GetContext napi_get_cb_info failed");
    int64_t value = 0;
    bool lossless = true;
    CHECK_AND_RETURN_RET_LOG(napi_ok == napi_get_value_bigint_int64(env, args[0], &value, &lossless),
        AVCODEC_SAMPLE_ERR_ERROR, "Get value failed");
    return value;
}
}

std::unordered_map<int64_t, PluginRender*> PluginManager::pluginRenderMap_;
std::unordered_map<int64_t, OHNativeWindow*> PluginManager::windowMap_;

PluginManager::~PluginManager()
{
    AVCODEC_SAMPLE_LOGI("~PluginManager");
    for (auto iter = pluginRenderMap_.begin(); iter != pluginRenderMap_.end(); ++iter) {
        if(iter->second != nullptr) {
            delete iter->second;
            iter->second = nullptr;
        }
    }
    pluginRenderMap_.clear();
    for (auto iter = windowMap_.begin(); iter != windowMap_.end(); ++iter) {
        if(iter->second != nullptr) {
            delete iter->second;
            iter->second = nullptr;
        }
    }
    windowMap_.clear();
}

PluginRender* PluginManager::GetPluginRender(int64_t &id)
{
    if(pluginRenderMap_.find(id) != pluginRenderMap_.end()) {
        return pluginRenderMap_[id];
    }
    return nullptr;
}

napi_value PluginManager::SetSurfaceId(napi_env env, napi_callback_info info)
{
    int64_t surfaceId = ParseId(env, info);
    OHNativeWindow *nativeWindow;
    PluginRender *pluginRender;
    if (windowMap_.find(surfaceId) == windowMap_.end()) {
        OH_NativeWindow_CreateNativeWindowFromSurfaceId(surfaceId, &nativeWindow);
        windowMap_[surfaceId] = nativeWindow;
    }
    if (pluginRenderMap_.find(surfaceId) == pluginRenderMap_.end()) {
        pluginRender = new PluginRender(surfaceId);
        pluginRenderMap_[surfaceId] = pluginRender;
    }
    pluginRender->InitNativeWindow(nativeWindow);
    return nullptr;
}

napi_value PluginManager::DestroySurface(napi_env env, napi_callback_info info)
{
    int64_t surfaceId = ParseId(env, info);
    auto pluginRenderMapIter = pluginRenderMap_.find(surfaceId);
    if(pluginRenderMapIter != pluginRenderMap_.end()) {
        delete pluginRenderMapIter->second;
        pluginRenderMap_.erase(pluginRenderMapIter);
    }
    auto windowMapIter = windowMap_.find(surfaceId);
    if (windowMapIter != windowMap_.end()) {
        OH_NativeWindow_DestroyNativeWindow(windowMapIter->second);
        windowMap_.erase(windowMapIter);
    }
    return nullptr;
}

napi_value PluginManager::ChangeSurface(napi_env env, napi_callback_info info)
{
    CHECK_AND_RETURN_RET_LOG(env != nullptr && info != nullptr, nullptr, "ChangeSurface: Onload env or info is null");
    int64_t surfaceId = 0;
    size_t argc = 3;
    napi_value args[3] = {nullptr};
    CHECK_AND_RETURN_RET_LOG(napi_ok == napi_get_cb_info(env, info, &argc, args, nullptr, nullptr),
        nullptr, "ChangeSurface: GetContext napi_get_cb_info failed");
    bool lossless = true;
    int index = 0;
    CHECK_AND_RETURN_RET_LOG(napi_ok == napi_get_value_bigint_int64(env, args[index++], &surfaceId, &lossless),
        nullptr, "ChangeSurface: Get value failed");
    double width;
    CHECK_AND_RETURN_RET_LOG(napi_ok == napi_get_value_double(env, args[index++], &width),
        nullptr, "ChangeSurface: Get width failed");
    double height;
    CHECK_AND_RETURN_RET_LOG(napi_ok == napi_get_value_double(env, args[index++], &height),
        nullptr, "ChangeSurface: Get height failed");
    auto pluginRender = GetPluginRender(surfaceId);
    CHECK_AND_RETURN_RET_LOG(pluginRender != nullptr, nullptr, "ChangeSurface: Get pluginRender failed");
    pluginRender->UpdateNativeWindowSize(width, height);
    return nullptr;
}

